assert(TrackCooldowns, "TrackCooldowns not found!")

local L = LibStub("AceLocale-3.0"):GetLocale("TrackCooldowns")
local Media = LibStub("LibSharedMedia-3.0")
local textures = Media:List("statusbar")
local fonts = Media:List("font")

local pairs, ipairs = _G.pairs, _G.ipairs
local tonumber, tostring = _G.tonumber, _G.tostring

local Display = TrackCooldowns:GetModule("Display")
local Report = TrackCooldowns:GetModule("Report")

Media.RegisterCallback(Display, "LibSharedMedia_Registered", "UpdateDisplay")
Media.RegisterCallback(Display, "LibSharedMedia_SetGlobal", "UpdateDisplay")

local function GetLSMIndex(t, value)
	for k, v in pairs(Media:List(t)) do
		if v == value then
			return k
		end
	end
	return nil
end

local function set(t, value)
	Display.db.profile[t[#t]] = value
	Display:UpdateDisplay()
end
local function get(t)
	return Display.db.profile[t[#t]]
end

local options = {
	type = "group",
	get = getProfileOption,
	set = setProfileOptionAndClearCache,

	args = {
		enabled = {
			type = "toggle",
			name = L["Enabled"],
			desc = L["Enable/Disable Track Cooldowns"],
			get = get,
			set = function(info, v)
				Display.db.profile.enabled = v
				if not v then Display.Reset()
				else Display:UpdateDisplay()
				end
			end,
			cmdHidden = true,
			order = 1,
			width = "full",
		},
		test = {
			type = "execute",
			name = L["Test"],
			desc = L["Test tracking bars"],
			order = 2,
			func = Display.Test,
		},
		reset = {
			type = "execute",
			name = L["Reset"],
			desc = L["Reset tracking bars"],
			order = 3,
			func = Display.Reset,
		},
		using = {
			type = "group",
			name = L["Using"],
			desc = L["AddOn using"],
			order = 1,
			cmdHidden = true,
			args = {
				inRaids = {
					type = "toggle",
					name = L["Show in raids"],
					desc = L["Track cooldowns in raids"],
					get = function(info) return Display.db.profile.inRaids end,
					set = function(info, v)
						Display.db.profile.inRaids = v
					end,
					order = 1,
					width = "full",
				},
				inParties = {
					type = "toggle",
					name = L["Show in parties"],
					desc = L["Track cooldowns in parties"],
					get = function(info) return Display.db.profile.inParties end,
					set = function(info, v)
						Display.db.profile.inParties = v
					end,
					order = 2,
					width = "full",
				},
				inBattlegrounds = {
					type = "toggle",
					name = L["Show in battlegrounds"],
					desc = L["Track cooldowns in battlegrounds"],
					get = function(info) return Display.db.profile.inBattlegrounds end,
					set = function(info, v)
						Display.db.profile.inBattlegrounds = v
					end,
					order = 1,
					width = "full",
				},
				solo = {
					type = "toggle",
					name = L["Show while alone"],
					desc = L["Track cooldowns while alone"],
					get = function(info) return Display.db.profile.solo end,
					set = function(info, v)
						Display.db.profile.solo = v
					end,
					order = 1,
					width = "full",
				},
			},
		},
		spells = {
			type = "group",
			name = L["Spell Options"],
			desc = L["Configure which spell cooldowns are shown and which aren't"],
			order = 2,
			cmdHidden = true,
			args = {
				showOwn = {
					type = "toggle",
					name = L["Show only your own spells"],
					desc = L["The addon will work as usual cooldown tracker"],
					order = 1,
					get = function(info) return Display.db.profile.showOwn end,
					set = function(info, v)
						Display.db.profile.showOwn = v
						if Display.db.profile.showOwn then
							Display.db.profile.hideSelf = false
						end
					end,
					width = "full",
					cmdHidden = true,
				},
				hideSelf = {
					type = "toggle",
					name = L["Hide self"],
					desc = L["Hide your own cooldowns"],
					order = 2,
					get = function(info) return Display.db.profile.hideSelf end,
					set = function(info, v)
						Display.db.profile.hideSelf = v
						if Display.db.profile.hideSelf then
							Display.db.profile.showOwn = false
						end
					end,
					width = "full",
					cmdHidden = true,
				},
				trackHealthstones = {
					type = "toggle",
					name = L["Show healthstones on report"],
					desc = L["Show healthstone usage on the report screen"],
					order = 2,
					get = function(info) return Display.db.profile.trackHealthstones end,
					set = function(info, v)
						Display.db.profile.trackHealthstones = v
					end,
					width = "full",
					cmdHidden = true,
				},
			},
		},
		display = {
			type = "group",
			name = L["Display Options"],
			desc = L["Display Options"],
			order = 3,
			cmdHidden = true,
			args = {
				locked = {
					type = "toggle",
					name = L["Lock Anchor"],
					desc = L["Locks the anchor in place and prevents it from being dragged"],
					get = get,
					set = set,
					order = 1,
					width = "full",
					cmdHidden = true,
				},
				growUp = {
					type = "toggle",
					name = L["Grow Up"],
					desc = L["Grow bars upwards"],
					get = get,
					set = set,
					order = 2,
					width = "full",
					cmdHidden = true,
				},
				groupByClass = {
					type = "toggle",
					name = L["Group by class"],
					desc = L["Group all bars by class first, then sort by time remaining."],
					get = get,
					set = function(info, v)
						Display.db.profile.groupByClass = v
						Display:ResortBars(v)
					end,
					order = 3,
					width = "full",
					cmdHidden = true,
				},
				scale = {
					type = "range",
					name = L["Scale"],
					desc = L["Control the scale of the entire TrackCooldowns GUI"],
					min = 1, max = 150, step = 1, bigStep = 1,
					get = get,
					set = set,
					order = 3,
					width = "full",
					cmdHidden = true,
				},
				alpha = {
					type = "range",
					name = L["Alpha"],
					desc = L["Control the transparency of the entire TrackCooldowns GUI"],
					min = 0, max = 100, step = 5, bigStep = 10,
					get = get,
					set = set,
					order = 4,
					width = "full",
					cmdHidden = true,
				},
				width = {
					type = "range",
					name = L["Width"],
					min = 50, max = 500, step = 5, bigStep = 10,
					get = get,
					set = set,
					order = 5,
					width = "full",
					cmdHidden = true,
				},
				height = {
					type = "range",
					name = L["Height"],
					min = 1, max = 20, step = 1, bigStep = 1,
					get = get,
					set = set,
					order = 6,
					width = "full",
					cmdHidden = true,
				},
				clamped = {
					type = 'toggle',
					name = L["Clamp to screen"],
					desc = L["Prevent the anchor from moving off screen"],
					get = get,
					set = set,
					order = 7,
					width = "full",
					cmdHidden = true,
				},
				posX = {
					type = 'input',
					name = L["X Position"],
					get = function(info) return tostring(Display.db.profile.posX) end,
					set = function(info, v)
						Display.db.profile.posX = tonumber(v)
						Display:SetAnchors(true)
					end,
					order = 8,
					width = "full",
					cmdHidden = true,
				},
				posY = {
					type = 'input',
					name = L["Y Position"],
					get = function(info) return tostring(Display.db.profile.posY) end,
					set = function(info, v)
						Display.db.profile.posY = tonumber(v)
						Display:SetAnchors(true)
					end,
					order = 9,
					width = "full",
					cmdHidden = true,
				},
				bars = {
					type = "group",
					name = L["Bar options"],
					desc = L["Options which affect the style of the cooldown bars"],
					order = 10,
					args = {
						texture = {
							type = "select",
							name = L["Texture"],
							desc = L["The texture that the bar will use"],
							values = textures,
							get = function(info) return GetLSMIndex("statusbar", Display.db.profile.texture) end,
							set = function(info, v)
								Display.db.profile.texture = Media:List("statusbar")[v]
								Display:UpdateDisplay()
							end,
							order = 1,
							width = "full",
							cmdHidden = true,
						},
						fontSize = {
							type = "range",
							name = L["Label Font Size"],
							desc = L["The size of the font that the bar labels will use"],
							min = 5, max = 30, step = 1, bigStep = 1,
							get = get,
							set = set,
							order = 2,
							width = "full",
							cmdHidden = true,
						},
						fontFace = {
							type = "select",
							name = L["Label Font"],
							desc = L["The font that the bar labels will use"],
							values = fonts,
							get = function(info) return GetLSMIndex("font", Display.db.profile.fontFace) end,
							set = function(info, v)
								Display.db.profile.fontFace = Media:List("font")[v]
								Display:UpdateDisplay()
							end,
							order = 3,
							width = "full",
							cmdHidden = true,
						},
						orientation = {
							type = "select",
							name = L["Orientation"],
							values = { L["Right to Left"], L["Left to Right"] },
							get = function(info) return (Display.db.profile.orientation == 3) and 2 or 1 end,
							set = function(info, v)
								Display.db.profile.orientation = (v == 2) and 3 or 1
								Display:UpdateDisplay()
							end,
							order = 4,
							width = nil,
							cmdHidden = true,
						},
					}
				},
				text = {
					type = "group",
					name = L["Hint options"],
					desc = L["Hints customising"],
					order = 11,
					args = {
						casterName = {
							type = "toggle",
							name = L["Show caster"],
							desc = L["Show caster name"],
							get = function(info) return Display.db.profile.casterName end,
							set = function(info, v)
								Display.db.profile.casterName = v
							end,
							order = 1,
							width = "full",
							cmdHidden = true,
						},
						spellName = {
							type = "toggle",
							name = L["Show spell"],
							desc = L["Show spell name"],
							get = function(info) return Display.db.profile.spellName end,
							set = function(info, v)
								Display.db.profile.spellName = v
							end,
							order = 2,
							width = "full",
							cmdHidden = true,
						},
						tooltip = {
							type = "toggle",
							name = L["Show tooltip"],
							desc = L["Show tooltip with spell name"],
							get = function(info) return Display.db.profile.tooltip end,
							set = function(info, v)
								Display.db.profile.tooltip = v
							end,
							order = 3,
							width = "full",
							cmdHidden = true,
						},
					},
				},
			},
		},
		reporting = {
			type = "group",
			name = L["Reporting"],
			desc = L["Reporting settings"],
			order = 4,
			cmdHidden = true,
			args = {
				readyMessage = {
					type = "toggle",
					name = L["Ready message"],
					desc = L["Print a chat message when cooldown is ready"],
					order = 1,
					get = function(info) return Display.db.profile.readyMessage end,
					set = function(info, v)
						Display.db.profile.readyMessage = v
					end,
					width = "full",
					cmdHidden = true,
				},
				startMessage = {
					type = "toggle",
					name = L["Start message"],
					desc = L["Print a chat message when someone casts tracking spell"],
					order = 2,
					get = function(info) return Display.db.profile.startMessage end,
					set = function(info, v)
						Display.db.profile.startMessage = v
					end,
					width = "full",
					cmdHidden = true,
				},
				onlyReportSelf = {
					type = "toggle",
					name = L["Report my CDs only"],
					desc = L["Only report your own cooldowns to the selected channel"],
					order = 2,
					get = function(info) return Display.db.profile.onlyReportSelf end,
					set = function(info, v)
						Display.db.profile.onlyReportSelf = v
					end,
					width = "full",
					cmdHidden = true,
				},
				reportChannel = {
					type = "select",
					name = L["Channel to report"],
					desc = L["Choose a chat channel for reporting messages"],
					order = 3,
					values = {
						["SELF"] = L["Self"],
						["INSTANCE_CHAT"] = L["Instance"],
						["RAID"] = L["Raid"],
						["RAID_WARNING"] = L["Raid Warning"],
						["PARTY"] = L["Party"],
						["SAY"] = L["Say"],
						["YELL"] = L["Yell"],
						["GUILD"] = L["Guild"],
						["OFFICER"] = L["Officer"],
					},
					get = function(info) return Display.db.profile.reportChannel end,
					set = function(info, v)
						Display.db.profile.reportChannel = v
						Display:SetBarScripts()
					end,
					width = nil,
					cmdHidden = true,
				},
				useCustomChannel = {
					type = "toggle",
					name = L["Use custom channel"],
					desc = L["Use your custom channel"],
					order = 4,
					get = function(info) return Display.db.profile.useCustomChannel end,
					set = function(info, v)
						Display.db.profile.useCustomChannel = v
					end,
					width = "full",
					cmdHidden = true,
				},
				customChannel = {
					type = "input",
					name = L["Custom channel to report"],
					desc = L["Custom chat channel number for reporting messages"],
					order = 5,
					get = function(info) return tostring(Display.db.profile.customChannel) end,
					set = function(info, v)
						if tonumber(v) then
							Display.db.profile.customChannel = tonumber(v)
							Display:SetBarScripts()
						else
							Display.db.profile.customChannel = ""
						end
					end,
					width = "full",
					cmdHidden = true,
				},
				
				announceClick = {
					type = "toggle",
					name = L["Click to announce"],
					desc = L["Enable clicking on a cooldown bar to announce the remaining duration."],
					get = function(info) return Display.db.profile.announceClick end,
					set = function(info, v)
						Display.db.profile.announceClick = v
						if not v then
							Display:RemoveBarScripts()
						else 
							Display:SetBarScripts()
						end
					end,
					cmdHidden = true,
					order = 1,
					width = "full",
				},
			},
		},
		config = {
			type = "execute",
			name = L["Configure"],
			desc = L["Open the configuration dialog"],
			func = Display.ShowConfig,
			guiHidden = true,
		},
		report = {
			type = "execute",
			name = L["Show report"],
			desc = L["Show a breakdown of cooldown usage"],
			func = Report.ShowReport,
			guiHidden = true,
		},
		toggle = {
			type = "execute",
			name = L["Enable/Disable Track Cooldowns"],
			desc = L["Enable or disable Track Cooldowns"],
			func = Display.TrackCooldownsToggle,
			guiHidden = true,
		},
		version = {
			type = "execute",
			name = L["Addon version"],
			desc = L["Show current version of Track Cooldowns"],
			func = Display.ShowVersion,
			hidden = true,
		},
	}
}

do
	local classes = {"DEATHKNIGHT", "DRUID", "HUNTER", "MAGE", "PALADIN", "PRIEST", "ROGUE", "SHAMAN", "WARLOCK", "WARRIOR", "MONK"}
	local t = options.args.spells.args
	local i = 6
	local Display = Display
	
	t["toggleOff"] = {
		type = "execute",
		name = L["Toggle Off"],
		desc = L["Turn all cooldowns off"],
		order = 4,
		func = function(info)
			for k, v in pairs(t) do
				if v.type == "toggle" and v.order > 6 then
					for k2, v2 in pairs(v) do
						if k2 == "set" then
							v:set(false)
						end
					end
				end
			end
		end,
	}
	
	t["toggleOn"] = {
		type = "execute",
		name = L["Toggle On"],
		desc = L["Turn all cooldowns on"],
		order = 5,
		func = function(info)
			for k, v in pairs(t) do
				if v.type == "toggle" and v.order > 6 then
					for k2, v2 in pairs(v) do
						if k2 == "set" then
							v:set(true)
						end
					end
				end
			end
		end,
	}
	
	for _, v in ipairs(classes) do
		t[v] = {
			type = "header",
			name = L[v],
			cmdHidden = true,
			order = i,
		}
		i = i + 1

		for k2, v2 in pairs(TrackCooldowns.cooldowns[v]) do
			t[tostring(v2.id)] = {
				type = "toggle",
				name = k2,
				desc = L["Display %s cooldowns"]:format(k2),
				order = i,
				get = function(info) return Display.db.profile.spells[v2.id] end,
				set = function(info, val)
					Display.db.profile.spells[v2.id] = val
					Display:SpellToggle(v2.id, val)
				end,
				cmdHidden = true,
			}
			i = i + 1
		end
	end
end

Display.configOptions = options
LibStub("AceConfig-3.0"):RegisterOptionsTable(L["Track Cooldowns"], options, "tc")